package cn.t.facade.user;


import cn.t.constants.CommonConstants;
import cn.t.converter.user.UserInfoDTOConverter;
import cn.t.converter.user.UserInfoRequestConverter;
import cn.t.converter.user.UserPassportDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.dto.user.CreateUserRequest;
import cn.t.dto.user.CustomerFirmDTO;
import cn.t.dto.user.CustomerIndividualDTO;
import cn.t.dto.user.CustomerInfoDTO;
import cn.t.dto.user.ParticipantInfoDTO;
import cn.t.dto.user.RoleInfoDTO;
import cn.t.dto.user.UserInfoDTO;
import cn.t.dto.user.UserPassportDTO;
import cn.t.core.enums.base.BaseStatusEnum;
import cn.t.core.enums.base.CommonError;
import cn.t.enums.user.RoleTypeEnum;
import cn.t.enums.user.UpdateEventTypeEnum;
import cn.t.model.user.CostCenterDO;
import cn.t.model.user.ParticipantInfoDO;
import cn.t.model.user.ParticipantRoleDO;
import cn.t.model.user.RoleFirmDO;
import cn.t.model.user.RoleInfoDO;
import cn.t.model.user.UserInfoDO;
import cn.t.service.user.CostCenterService;
import cn.t.service.user.CustomerInfoService;
import cn.t.service.user.ParticipantInfoService;
import cn.t.service.user.ParticipantRoleService;
import cn.t.service.user.RoleFirmService;
import cn.t.service.user.RoleInfoService;
import cn.t.service.user.UserInfoService;
import cn.t.service.user.UserPassportService;
import cn.t.service.user.UserQueryService;
import cn.t.user.event.UserQueryUpdateEvent;
import cn.t.vo.ent.EntUserOverviewVO;
import cn.t.vo.user.ParticipantWithUserVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户信息表服务编排
 *
 * @author l
 */
@Slf4j
@Service
@AllArgsConstructor
public class UserInfoFacade extends FacadeImpl<UserInfoDTO, UserInfoDO, UserInfoDTOConverter, UserInfoService> {

    public UserInfoDTO createByFirmDevice(Long firmId, Long deviceId) {
        String cardCode = "DummyCard:" + deviceId;
        ParticipantWithUserVO participant = userQueryService.findMaterIssuerByFirmCard(firmId, cardCode);
        if (participant != null && participant.getUserId() != null) {
            return queryOne(participant.getUserId());
        }

        CreateUserRequest request = new CreateUserRequest();
        request.setCardCode(cardCode);

        Map<Integer, UserPassportDTO> passportMap = userInfoRequestConverter.convertPassport(request);
        UserInfoDTO userInfo = userInfoRequestConverter.convertUserInfo(request);
        CustomerIndividualDTO customerIndividual = userInfoRequestConverter.convertCustomerInfo(request);
        RoleInfoDTO roleInfoDTO = userInfoRequestConverter.convertRoleInfoDTO(request);

        CustomerFirmDTO customerFirm = new CustomerFirmDTO();
        customerFirm.setId(firmId);

        return create(passportMap, userInfo, null,roleInfoDTO, customerIndividual, customerFirm);

    }


    @Transactional
    public UserInfoDTO create(Map<Integer, UserPassportDTO> passportMap, UserInfoDTO userInfo, ParticipantInfoDTO participantInfoDTO, RoleInfoDTO roleInfo, CustomerIndividualDTO customerIndividual, CustomerFirmDTO customerFirmDTO) {

        if (participantInfoDTO != null && participantInfoDTO.getCostCenterId() != null) {
            CostCenterDO costCenterDO = costCenterService.findById(participantInfoDTO.getCostCenterId());
            if (costCenterDO == null) {
                String errorMessage = String.format("指定的成本中心不存在 costCenterId=%s ", participantInfoDTO.getCostCenterId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            if (customerFirmDTO == null || customerFirmDTO.getId() == null) {
                customerFirmDTO = new CustomerFirmDTO();
                customerFirmDTO.setId(costCenterDO.getFirmId());
            }

            if (!customerFirmDTO.getId().equals(costCenterDO.getFirmId())) {
                String errorMessage = String.format("指定的成本中心企业不匹配 costCenterId=%s firmId=%s", participantInfoDTO.getCostCenterId(), customerFirmDTO.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }
        }

        RoleInfoDO roleInfoDO = null;
        if (roleInfo != null && ObjectUtils.isNotEmpty(roleInfo.getId())) {

            roleInfoDO = roleInfoService.findById(roleInfo.getId());

            if (roleInfoDO == null || ObjectUtils.isEmpty(roleInfoDO.getId())) {
                String errorMessage = String.format("指定的角色不存在 roleId=%s", roleInfo.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            List<RoleFirmDO> roleFirm = roleFirmService.findByRoleId(roleInfo.getId());
            if (CollectionUtils.isEmpty(roleFirm)) {
                String errorMessage = String.format("指定的角色未关联任何企业 roleId=%s", roleInfo.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            if ((customerFirmDTO == null || customerFirmDTO.getId() == null) && roleFirm.size() > 1) {
                String errorMessage = String.format("指定的角色关联多家企业 roleId=%s", roleInfo.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            if (customerFirmDTO == null || customerFirmDTO.getId() == null) {
                customerFirmDTO = new CustomerFirmDTO();
                customerFirmDTO.setId(roleFirm.get(0).getFirmId());
            }

            if (!customerFirmDTO.getId().equals(roleFirm.get(0).getFirmId())) {
                String errorMessage = String.format("指定的角色已关联企业，且两企业不匹配 roleId=%s firmId=%s", roleInfo.getId(), customerFirmDTO.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

        }

        CustomerFirmDTO finalCustomerFirmDTO = customerFirmDTO;
        passportMap.values().forEach(passportDTO -> userPassportService.hasDuplicatedPassport(userInfo.getId(), finalCustomerFirmDTO, userPassportDtoConverter.dto2Model(passportDTO)));
        CustomerInfoDTO customerInfo = customerInfoFacade.createIndividual(customerIndividual);
        userInfo.setIndividualId(customerInfo.getId());

        UserInfoDO userInfoDO = service.createUser(converter.dto2Model(userInfo));
        Long userId = userInfoDO.getId();

        for (UserPassportDTO passportDTO : passportMap.values()) {
            userPassportService.add(userId, userPassportDtoConverter.dto2Model(passportDTO));
        }

        if (participantInfoDTO != null && participantInfoDTO.getCostCenterId() != null) {
            participantInfoService.getOrAddByCostCenter(userId, customerInfo.getId(), participantInfoDTO.getCostCenterId());
        }

        if (customerFirmDTO != null && customerFirmDTO.getId() != null) {
            ParticipantInfoDO participantInfoDO = participantInfoService.getOrAdd(userId, customerInfo.getId(), customerFirmDTO.getId());

            // 增加用户角色
            if (roleInfoDO != null && roleInfoDO.getId() != null) {
                Map<Long, ParticipantInfoDO> firmParticipantInfo = new LinkedHashMap<>();
                firmParticipantInfo.put(customerFirmDTO.getId(), participantInfoDO);
                participantRoleService.addRole(userInfoDO, roleInfoDO, firmParticipantInfo);
            }
        }


        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userId, userSessionFacade.operatorInfo(), userId, UpdateEventTypeEnum.ADD, UpdateEventTypeEnum.ADD, UpdateEventTypeEnum.ADD));

        return queryOne(userId);
    }

    @Transactional
    public void update(Map<Integer, UserPassportDTO> passportMap, UserInfoDTO userInfo, ParticipantInfoDTO participantInfoDTO, CustomerIndividualDTO customerIndividual, CustomerFirmDTO customerFirmDTO) {

        UserInfoDO userDatabase = isValidUserInfo(userInfo.getId(), customerIndividual.getId());

        if (participantInfoDTO != null && participantInfoDTO.getCostCenterId() != null) {
            CostCenterDO costCenterDO = costCenterService.findById(participantInfoDTO.getCostCenterId());
            if (costCenterDO == null) {
                String errorMessage = String.format("指定的成本中心不存在 costCenterId=%s ", participantInfoDTO.getCostCenterId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }

            if (customerFirmDTO == null || customerFirmDTO.getId() == null) {
                customerFirmDTO = new CustomerFirmDTO();
                customerFirmDTO.setId(costCenterDO.getFirmId());
            } else if (!customerFirmDTO.getId().equals(costCenterDO.getFirmId())) {
                String errorMessage = String.format("指定的成本中心企业不匹配 costCenterId=%s firmId=%s", participantInfoDTO.getCostCenterId(), customerFirmDTO.getId());
                log.error(errorMessage);
                throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
            }
        }

        if (!CollectionUtils.isEmpty(passportMap)) {
            for (Map.Entry<Integer, UserPassportDTO> entry : passportMap.entrySet()) {
                userPassportService.hasDuplicatedPassport(userInfo.getId(), customerFirmDTO, userPassportDtoConverter.dto2Model(entry.getValue()));
            }

            Set<Long> passportIds = new HashSet<>();
            for (Map.Entry<Integer, UserPassportDTO> entry : passportMap.entrySet()) {
                Long passportId = userPassportService.update(userInfo.getId(), userPassportDtoConverter.dto2Model(entry.getValue()));
                if (passportId != null && passportId > 0) {
                    passportIds.add(passportId);
                }
            }
            userPassportService.removeWithout(userInfo.getId(), passportIds);
        }

        customerIndividualFacade.updateCustomer(customerIndividual);

        if (StringUtils.isNotBlank(userInfo.getLoginPassword())) {
            service.changePassword(userInfo.getId(), userInfo.getLoginPassword());
        }

        participantInfoService.clearCostCenter(userInfo.getId());
        if (participantInfoDTO != null && participantInfoDTO.getCostCenterId() != null) {
            participantInfoService.getOrAddByCostCenter(userInfo.getId(), customerIndividual.getId(), participantInfoDTO.getCostCenterId());
        }

        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userDatabase.getId(), userSessionFacade.operatorInfo(), userDatabase.getId(), UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));
    }

    @Transactional
    public void deleteUser(Long userId) {
        UserInfoDO userInfoDO = service.findById(userId);

        if (userInfoDO == null || !userInfoDO.getId().equals(userId)) {
            String errorMessage = String.format("指定的用户不存在 userId=%s", userId);
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        customerInfoService.deleteIndividualCustomer(userInfoDO.getIndividualId());
        userPassportService.deletePassportByUserId(userId);
        // 需要先删除用户角色，再删除参与者数据
        participantRoleService.deleteRoleByUserId(userId);
        participantInfoService.deleteParticipantByUserId(userId);

        service.deleteUser(userId);
        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userId, userSessionFacade.operatorInfo(), userId, UpdateEventTypeEnum.DELETE, UpdateEventTypeEnum.DELETE, UpdateEventTypeEnum.DELETE));
    }

    public boolean disableUser(Long userId) {
        UserInfoDO userInfoDO = service.findById(userId);


        if (userInfoDO == null || !userInfoDO.getId().equals(userId)) {
            String errorMessage = String.format("指定的用户不存在 userId=%s", userId);
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        customerInfoService.disableIndividualCustomer(userInfoDO.getIndividualId());
        userPassportService.disablePassportByUserId(userId);
        // 需要先删除用户角色，再删除参与者数据
        participantRoleService.disableRoleByUserId(userId);
        participantInfoService.disableParticipantByUserId(userId);

        boolean result = service.disableUser(userId);

        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userId, userSessionFacade.operatorInfo(), userId, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));

        return result;
    }


    public boolean enableUser(Long userId) {

        UserInfoDO userInfoDO = service.findById(userId);

        if (userInfoDO == null || !userInfoDO.getId().equals(userId)) {
            String errorMessage = String.format("指定的用户不存在 userId=%s", userId);
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        customerInfoService.enableIndividualCustomer(userInfoDO.getIndividualId());
        userPassportService.enablePassportByUserId(userId);
        // 需要先删除用户角色，再删除参与者数据
        participantRoleService.enableRoleByUserId(userId);
        participantInfoService.enableParticipantByUserId(userId);

        boolean result = service.enableUser(userId);

        applicationEventPublisher.publishEvent(new UserQueryUpdateEvent(userId, userSessionFacade.operatorInfo(), userId, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE, UpdateEventTypeEnum.UPDATE));

        return result;
    }

    public UserInfoDO isValidUserInfo(Long userId, Long individualId) {
        UserInfoDO userInfoDO = service.findById(userId);
        if (userInfoDO == null || !userInfoDO.getId().equals(userId)
                || !individualId.equals(userInfoDO.getIndividualId())) {
            String errorMessage = String.format("指定的用户不存在 userId=%s", userId);
            log.error(errorMessage);
            throw new BizException(CommonError.ILLEGAL_PARAMETER, errorMessage);
        }

        return userInfoDO;
    }

    public void changePassword(Long userId, String password) {
        service.changePassword(userId, password);
    }

    public EntUserOverviewVO overview(Long firmId) {
        // 查询公司角色
        List<RoleFirmDO> roleFirmDOS = roleFirmService.list(firmId);
        if (CollectionUtils.isEmpty(roleFirmDOS)) {
            return new EntUserOverviewVO(CommonConstants.ZERO, CommonConstants.ZERO, CommonConstants.ZERO);
        }
        List<Long> firmRoleIds = roleFirmDOS.stream().map(RoleFirmDO::getRoleId).collect(Collectors.toList());

        // 查询领料员角色
        List<RoleInfoDO> roleInfoDOS = this.roleInfoService.findByType(RoleTypeEnum.MATERIAL_ISSUE.getCode());
        List<Long> roleIds = roleInfoDOS.stream().filter(f -> firmRoleIds.contains(f.getId())).map(RoleInfoDO::getId).collect(Collectors.toList());
        List<ParticipantRoleDO> participantRoleDOS = this.participantRoleService.findByRoleIds(roleIds);
        Set<Long> userIds = participantRoleDOS.stream().map(ParticipantRoleDO::getUserId).collect(Collectors.toSet());
        int total = userIds.size();
        long enableNum = participantRoleDOS.stream().filter(f -> String.valueOf(BaseStatusEnum.AVAILABLE.getCode()).equals(f.getStatus())).map(ParticipantRoleDO::getUserId).collect(Collectors.toSet()).size();
        long disableNum = participantRoleDOS.stream().filter(f -> String.valueOf(BaseStatusEnum.DISABLE.getCode()).equals(f.getStatus())).map(ParticipantRoleDO::getUserId).collect(Collectors.toSet()).size();
        return new EntUserOverviewVO(total, (int) enableNum, (int) disableNum);
    }

    @Autowired
    private CostCenterService costCenterService;

    @Autowired
    private CustomerInfoFacade customerInfoFacade;

    @Autowired
    private UserPassportService userPassportService;

    @Autowired
    private CustomerInfoService customerInfoService;

    @Autowired
    private CustomerIndividualFacade customerIndividualFacade;

    @Autowired
    private ParticipantRoleService participantRoleService;

    @Autowired
    private ParticipantInfoService participantInfoService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private UserSessionFacade userSessionFacade;

    @Autowired
    private UserQueryService userQueryService;

    @Autowired
    private UserInfoRequestConverter userInfoRequestConverter;

    @Autowired
    private UserPassportDTOConverter userPassportDtoConverter;
    @Resource
    private RoleInfoService roleInfoService;
    @Resource
    private RoleFirmService roleFirmService;


}

